package org.example.interceptor;

import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.binding.MapperProxyFactory;
import org.apache.ibatis.binding.MapperRegistry;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Statement;
import java.util.*;
import java.util.stream.Collectors;

// 只有 Select 才会走这里
@Component
@Intercepts({
        @Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class})})
public class StatementHandlerInterceptor implements Interceptor {

    DefaultObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
    DefaultObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
    DefaultReflectorFactory DEFAULT_REFLECTOR_FACTORY = new DefaultReflectorFactory();

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget();
        Object result = invocation.proceed();
        Object[] res = new Object[1];
        if (!(result instanceof List)) {
            return result;
        } else {
            res[0] = new ArrayList<>((List<Object>) result);
        }

        BoundSql boundSql = ((RoutingStatementHandler) target).getBoundSql();
        String sql = boundSql.getSql();
        MySqlStatementParser parser = new MySqlStatementParser(sql);
        SQLSelectStatement selectStatement = (SQLSelectStatement) parser.parseStatement();
        SQLSelectQuery query = selectStatement.getSelect().getQuery();
        boolean isUnion = query instanceof SQLUnionQuery;
        boolean pass = false;
        String id = "";
        boolean returnValIsList = false;
        ParameterHandler parameterHandler = ((RoutingStatementHandler) target).getParameterHandler();
        if (parameterHandler instanceof DefaultParameterHandler) {
            Field mappedStatementField = parameterHandler.getClass().getDeclaredField("mappedStatement");
            mappedStatementField.setAccessible(true);
            MappedStatement mappedStatement = (MappedStatement) mappedStatementField.get(parameterHandler);
            id = mappedStatement.getId();
            Configuration configuration = mappedStatement.getConfiguration();
            MapperRegistry mapperRegistry = configuration.getMapperRegistry();
            Field knownMappersField = mapperRegistry.getClass().getDeclaredField("knownMappers");
            knownMappersField.setAccessible(true);
            Map<Class<?>, MapperProxyFactory<?>> mapperProxyFactoryMap = (Map<Class<?>, MapperProxyFactory<?>>) knownMappersField.get(mapperRegistry);

            for (MapperProxyFactory<?> value : mapperProxyFactoryMap.values()) {
                for (Map.Entry<Method, MapperMethod> entry : value.getMethodCache().entrySet()) {
                    Method method = entry.getKey();
                    if ((method.getDeclaringClass().getName() + "." + method.getName()).equalsIgnoreCase(id)) {
                        // 如果返回值不是 List，不放行
                        if (!isUnion && List.class.isAssignableFrom(method.getReturnType())) {
                            pass = true;
                        }
                        returnValIsList = List.class.isAssignableFrom(method.getReturnType());
                    }
                }
            }
            System.out.println(mapperProxyFactoryMap);
        }
        if (pass) {
            return result;
        }
        // 剩下的都是 SelectOne 却返回 List ，要归并结果
        if (isUnion) {
            MySqlSelectQueryBlock sqlSelectQuery = (MySqlSelectQueryBlock) ((SQLUnionQuery) query).getRelations().get(1);
            List<SQLSelectItem> selectList = sqlSelectQuery.getSelectList();
            int size = selectList.size();
            String finalId = id;
            reWriteLimit(sqlSelectQuery, finalId, res);
            reWriteOrderBy(sqlSelectQuery, res);
            for (SQLSelectItem sqlSelectItem : selectList) {
                boolean finalReturnValIsList = returnValIsList;
                reWriteAggregate(sqlSelectItem, res, finalReturnValIsList, size);
                reWriteGroupBy(sqlSelectItem, res);
            }
        }
        return res[0];
    }

    private void reWriteAggregate(SQLSelectItem sqlSelectItem, Object[] res, boolean finalReturnValIsList, int size) {
        sqlSelectItem.accept(new SQLASTVisitorAdapter() {
            // 对 avg 字段根据 group by 重新计算，另外 group by的组不能有重复的
            @Override
            public boolean visit(SQLAggregateExpr expr) {
                SQLSelectItem selectItem = findSelectItem(expr);
                // 一般来说，avg() 肯定是有别名的
                String alias = "";
                if (selectItem.getAlias() != null) {
                    alias = selectItem.getAlias();
                }
                if (alias.equals("plugin_generate_sum") || alias.equals("plugin_generate_count")) {
                    return super.visit(expr);
                }
                MySqlSelectQueryBlock parent = SqlUtil.findParent(expr);
                SQLSelectGroupByClause groupBy = parent.getGroupBy();
                List<String> groupByItems = new ArrayList<>();
                if (Objects.nonNull(groupBy)) {
                    List<SQLExpr> items = groupBy.getItems();
                    for (SQLExpr item : items) {
                        if (item instanceof SQLIdentifierExpr) {
                            groupByItems.add(((SQLIdentifierExpr) item).getName());
                        } else {
                            throw new RuntimeException("还要其他类型");
                        }
                    }
                }
                String methodName = expr.getMethodName();
                List<Object> tmp = (List<Object>) res[0];
                Map<String, List<Object>> map = null;
                if (groupBy != null) {
                    map = getGroupByMap(tmp, groupByItems);
                }

                if (methodName.equalsIgnoreCase("count")) { // 返回值必须是long，单对象，对象列表
                    long count = 0L;
                    if (!finalReturnValIsList && (isLong(tmp.get(0)) || isInteger(tmp.get(0)))) {
                        for (Object ele : tmp) {
                            count += (long) ele;
                        }
                        ((List<?>) res[0]).clear();
                        ((List<Long>) res[0]).add(count);
                        return super.visit(expr);
                    } else if (!finalReturnValIsList) {
                        for (Object ele : tmp) {
                            MetaObject metaObject = MetaObject.forObject(ele, DEFAULT_OBJECT_FACTORY,
                                    DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                            if (metaObject.hasGetter(alias)) {
                                Object value = metaObject.getValue(alias);
                                if (value == null) {
                                    value = 0L;
                                }
                                count += (long) value;
                            } else {
                                throw new RuntimeException("聚集函数无别名");
                            }
                        }
                        Object obj = tmp.get(0);
                        MetaObject metaObject = MetaObject.forObject(obj, DEFAULT_OBJECT_FACTORY,
                                DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                        metaObject.setValue(alias, count);
                        ((List<?>) res[0]).clear();
                        ((List<Object>) res[0]).add(obj);
                        return super.visit(expr);
                    }

                    if (groupBy != null) {
                        List<Object> newRes = new ArrayList<>();
                        if (tmp.size() != map.size()) {
                            for (Map.Entry<String, List<Object>> entry : map.entrySet()) {
                                List<Object> value = entry.getValue();
                                if (value.size() == 1) {
                                    newRes.add(value.get(0));
                                } else {
                                    count = 0L;
                                    for (Object ele : value) {
                                        MetaObject metaObject = MetaObject.forObject(ele, DEFAULT_OBJECT_FACTORY,
                                                DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                                        if (metaObject.hasGetter(alias)) {
                                            Object val = metaObject.getValue(alias);
                                            if (val == null) {
                                                val = 0L;
                                            }
                                            count += (long) val;
                                        } else {
                                            throw new RuntimeException("聚集函数无别名");
                                        }
                                    }
                                    Object obj = value.get(0);
                                    MetaObject metaObject = MetaObject.forObject(obj, DEFAULT_OBJECT_FACTORY,
                                            DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                                    metaObject.setValue(alias, count);
                                    newRes.add(obj);
                                }
                            }
                        } else {
                            newRes = tmp;
                        }
                        res[0] = newRes;
                    }
                } else if (methodName.equalsIgnoreCase("avg")) { // 返回值必须是对象
                    if (size > 1) {
                        if (groupBy == null) {
                            double sum = 0;
                            long count = 0;
                            for (Object ele : ((List) res[0])) {
                                MetaObject metaObject = MetaObject.forObject(ele, DEFAULT_OBJECT_FACTORY,
                                        DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                                if (metaObject.hasGetter("pluginGenerateSum")) {
                                    Object value = metaObject.getValue("pluginGenerateSum");
                                    if (value == null) {
                                        value = 0D;
                                    }
                                    sum += (double) value;
                                }
                                if (metaObject.hasGetter("pluginGenerateCount")) {
                                    Object value = metaObject.getValue("pluginGenerateCount");
                                    count += (long) value;
                                }
                            }
                            MetaObject metaObject = MetaObject.forObject(((List) res[0]).get(0), DEFAULT_OBJECT_FACTORY,
                                    DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                            // 给有 avg 别名的设置值,返回一个对象就行
                            metaObject.setValue(alias, sum / count);
                            res[0] = ((List) res[0]).get(0);
                            return super.visit(expr);
                        }

                        List<Object> newRes = new ArrayList<>();
                        if (map.size() != tmp.size()) {
                            for (Map.Entry<String, List<Object>> entry : map.entrySet()) {
                                List<Object> value = entry.getValue();
                                if (value.size() == 1) {
                                    newRes.add(value.get(0));
                                } else {
                                    double subSum = 0d;
                                    long subCount = 0L;
                                    for (Object obj : value) {
                                        MetaObject metaObject = MetaObject.forObject(obj, DEFAULT_OBJECT_FACTORY,
                                                DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                                        if (metaObject.hasGetter("pluginGenerateSum")) {
                                            Object val = metaObject.getValue("pluginGenerateSum");
                                            if (val == null) {
                                                val = 0D;
                                            }
                                            subSum += (double) val;
                                        }
                                        if (metaObject.hasGetter("pluginGenerateCount")) {
                                            Object val = metaObject.getValue("pluginGenerateCount");
                                            subCount += (long) val;
                                        }
                                    }
                                    Object obj = value.get(0);
                                    MetaObject metaObject = MetaObject.forObject(obj, DEFAULT_OBJECT_FACTORY,
                                            DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                                    try {
                                        Field declaredField = obj.getClass().getDeclaredField(alias);
                                        declaredField.setAccessible(true);
                                        Class<?> type = declaredField.getType();
                                        if (type.isAssignableFrom(Long.class)) {
                                            // 给有 avg 别名的设置值,返回一个对象就行
                                            metaObject.setValue(alias, (long) (subSum / subCount));
                                        } else if (type.isAssignableFrom(Integer.class)) {
                                            metaObject.setValue(alias, (int) (subSum / subCount));
                                        } else if (type.isAssignableFrom(Float.class)) {
                                            metaObject.setValue(alias, (float) (subSum / subCount));
                                        } else if (type.isAssignableFrom(Double.class)) {
                                            metaObject.setValue(alias, subSum / subCount);
                                        }
                                    } catch (NoSuchFieldException e) {
                                        throw new RuntimeException(e);
                                    }
                                    newRes.add(obj);
                                }
                            }
                        } else {
                            newRes = tmp;
                        }
                        res[0] = newRes;
                    }
                } else if (methodName.equalsIgnoreCase("sum")) {
                    long sum = 0L;
                    if (!finalReturnValIsList && (isLong(tmp.get(0)) || isInteger(tmp.get(0)))) {
                        for (Object ele : tmp) {
                            sum += (long) ele;
                        }
                        ((List<?>) res[0]).clear();
                        ((List<Long>) res[0]).add(sum);
                        return super.visit(expr);
                    } else if (!finalReturnValIsList) {
                        for (Object ele : tmp) {
                            MetaObject metaObject = MetaObject.forObject(ele, DEFAULT_OBJECT_FACTORY,
                                    DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                            if (metaObject.hasGetter(alias)) {
                                Object value = metaObject.getValue(alias);
                                if (value == null) {
                                    value = 0L;
                                }
                                sum += (long) value;
                            } else {
                                throw new RuntimeException("聚集函数无别名");
                            }
                        }
                        Object obj = tmp.get(0);
                        MetaObject metaObject = MetaObject.forObject(obj, DEFAULT_OBJECT_FACTORY,
                                DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                        metaObject.setValue(alias, sum);
                        ((List<?>) res[0]).clear();
                        ((List<Object>) res[0]).add(obj);
                        return super.visit(expr);
                    }

                    if (groupBy != null) {
                        List<Object> newRes = new ArrayList<>();
                        if (tmp.size() != map.size()) {
                            for (Map.Entry<String, List<Object>> entry : map.entrySet()) {
                                List<Object> value = entry.getValue();
                                if (value.size() == 1) {
                                    newRes.add(value.get(0));
                                } else {
                                    sum = 0L;
                                    for (Object ele : value) {
                                        MetaObject metaObject = MetaObject.forObject(ele, DEFAULT_OBJECT_FACTORY,
                                                DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                                        if (metaObject.hasGetter(alias)) {
                                            Object val = metaObject.getValue(alias);
                                            if (val == null) {
                                                val = 0L;
                                            }
                                            sum += (long) val;
                                        } else {
                                            throw new RuntimeException("聚集函数无别名");
                                        }
                                    }
                                    Object obj = value.get(0);
                                    MetaObject metaObject = MetaObject.forObject(obj, DEFAULT_OBJECT_FACTORY,
                                            DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                                    metaObject.setValue(alias, sum);
                                    newRes.add(obj);
                                }
                            }
                        } else {
                            newRes = tmp;
                        }
                        res[0] = newRes;
                    }

                } else if (methodName.equalsIgnoreCase("max")) {
                    long max = 0L;
                    if (!finalReturnValIsList && (isLong(tmp.get(0)) || isInteger(tmp.get(0)))) {
                        for (Object ele : tmp) {
                            max = Math.max((long) ele, max);
                        }
                        ((List<?>) res[0]).clear();
                        ((List<Long>) res[0]).add(max);
                        return super.visit(expr);
                    } else if (!finalReturnValIsList) {
                        for (Object ele : tmp) {
                            MetaObject metaObject = MetaObject.forObject(ele, DEFAULT_OBJECT_FACTORY,
                                    DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                            if (metaObject.hasGetter(alias)) {
                                Object value = metaObject.getValue(alias);
                                if (value == null) {
                                    value = 0L;
                                }
                                max = Math.max((long) value, max);
                            } else {
                                throw new RuntimeException("聚集函数无别名");
                            }
                        }
                        Object obj = tmp.get(0);
                        MetaObject metaObject = MetaObject.forObject(obj, DEFAULT_OBJECT_FACTORY,
                                DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                        metaObject.setValue(alias, max);
                        ((List<?>) res[0]).clear();
                        ((List<Object>) res[0]).add(obj);
                        return super.visit(expr);
                    }

                    if (groupBy != null) {
                        List<Object> newRes = new ArrayList<>();
                        if (tmp.size() != map.size()) {
                            for (Map.Entry<String, List<Object>> entry : map.entrySet()) {
                                List<Object> value = entry.getValue();
                                if (value.size() == 1) {
                                    newRes.add(value.get(0));
                                } else {
                                    max = 0L;
                                    for (Object ele : value) {
                                        MetaObject metaObject = MetaObject.forObject(ele, DEFAULT_OBJECT_FACTORY,
                                                DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                                        if (metaObject.hasGetter(alias)) {
                                            Object val = metaObject.getValue(alias);
                                            if (val == null) {
                                                val = 0L;
                                            }
                                            max = Math.max((long) val, max);
                                        } else {
                                            throw new RuntimeException("聚集函数无别名");
                                        }
                                    }
                                    Object obj = value.get(0);
                                    MetaObject metaObject = MetaObject.forObject(obj, DEFAULT_OBJECT_FACTORY,
                                            DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                                    metaObject.setValue(alias, max);
                                    newRes.add(obj);
                                }
                            }
                        } else {
                            newRes = tmp;
                        }
                        res[0] = newRes;
                    }
                } else if (methodName.equalsIgnoreCase("min")) {
                    long min = 0L;
                    if (!finalReturnValIsList && (isLong(tmp.get(0)) || isInteger(tmp.get(0)))) {
                        for (Object ele : tmp) {
                            min = Math.min((long) ele, min);
                        }
                        ((List<?>) res[0]).clear();
                        ((List<Long>) res[0]).add(min);
                        return super.visit(expr);
                    } else if (!finalReturnValIsList) {
                        for (Object ele : tmp) {
                            MetaObject metaObject = MetaObject.forObject(ele, DEFAULT_OBJECT_FACTORY,
                                    DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                            if (metaObject.hasGetter(alias)) {
                                Object value = metaObject.getValue(alias);
                                if (value == null) {
                                    value = 0L;
                                }
                                min = Math.min((long) value, min);
                            } else {
                                throw new RuntimeException("聚集函数无别名");
                            }
                        }
                        Object obj = tmp.get(0);
                        MetaObject metaObject = MetaObject.forObject(obj, DEFAULT_OBJECT_FACTORY,
                                DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                        metaObject.setValue(alias, min);
                        ((List<?>) res[0]).clear();
                        ((List<Object>) res[0]).add(obj);
                        return super.visit(expr);
                    }

                    if (groupBy != null) {
                        List<Object> newRes = new ArrayList<>();
                        if (tmp.size() != map.size()) {
                            for (Map.Entry<String, List<Object>> entry : map.entrySet()) {
                                List<Object> value = entry.getValue();
                                if (value.size() == 1) {
                                    newRes.add(value.get(0));
                                } else {
                                    min = 0L;
                                    for (Object ele : value) {
                                        MetaObject metaObject = MetaObject.forObject(ele, DEFAULT_OBJECT_FACTORY,
                                                DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                                        if (metaObject.hasGetter(alias)) {
                                            Object val = metaObject.getValue(alias);
                                            if (val == null) {
                                                val = 0L;
                                            }
                                            min = Math.min((long) val, min);
                                        } else {
                                            throw new RuntimeException("聚集函数无别名");
                                        }
                                    }
                                    Object obj = value.get(0);
                                    MetaObject metaObject = MetaObject.forObject(obj, DEFAULT_OBJECT_FACTORY,
                                            DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                                    metaObject.setValue(alias, min);
                                    newRes.add(obj);
                                }
                            }
                        } else {
                            newRes = tmp;
                        }
                        res[0] = newRes;
                    }
                }
                return super.visit(expr);
            }
        });
    }

    private void reWriteGroupBy(SQLSelectItem sqlSelectItem, Object[] res) {
        sqlSelectItem.accept(new SQLASTVisitorAdapter() {

            // 不处理 select 有 聚合函数的 SQL
            @Override
            public boolean visit(SQLSelectGroupByClause groupBy) {
                MySqlSelectQueryBlock parent = SqlUtil.findParent(groupBy);
                List<SQLSelectItem> selectList = parent.getSelectList();
                for (SQLSelectItem selectItem : selectList) {
                    String sqlString = SQLUtils.toSQLString(selectItem.getExpr());
                    if (sqlString.contains("count(") || (sqlString.contains("avg(")) ||
                            sqlString.contains("min(") || sqlString.contains("max(") || sqlString.contains("sum(")) {
                        return super.visit(groupBy);
                    }
                }
                List<Object> tmp = (List<Object>) res[0];
                // 多字段分组
                ArrayList<String> groupByItems = new ArrayList<>();
                List<SQLExpr> items = groupBy.getItems();
                for (SQLExpr item : items) {
                    if (item instanceof SQLIdentifierExpr) {
                        groupByItems.add(((SQLIdentifierExpr) item).getName());
                    } else {
                        throw new RuntimeException("还要其他类型");
                    }
                }
                Map<String, List<Object>> map = getGroupByMap(tmp, groupByItems);
                List<Object> newRes = new ArrayList<>();
                if (tmp.size() != map.size()) {
                    for (Map.Entry<String, List<Object>> entry : map.entrySet()) {
                        List<Object> value = entry.getValue();
                        newRes.add(value.get(0));
                    }
                } else {
                    newRes = tmp;
                }
                res[0] = newRes;
                return super.visit(groupBy);
            }
        });
    }

    private void reWriteOrderBy(MySqlSelectQueryBlock sqlSelectQuery, Object[] res) {
        sqlSelectQuery.accept(new SQLASTVisitorAdapter() {
            // order by 对结果集 多字段重排序
            @Override
            public boolean visit(SQLOrderBy orderBy) {
                List<SQLSelectOrderByItem> items = orderBy.getItems();
                ArrayList<String> list = new ArrayList<>();
                for (SQLSelectOrderByItem item : items) {
                    SQLExpr itemExpr = item.getExpr();
                    if (itemExpr instanceof SQLIdentifierExpr) {
                        list.add(((SQLIdentifierExpr) itemExpr).getName());
                    } else {
                        throw new RuntimeException("未知类型");
                    }
                }
                List<Object> tmp = (List<Object>) res[0];
                List<Object> collect = tmp.stream().sorted(new Comparator<Object>() {
                    @Override
                    public int compare(Object o1, Object o2) {
                        MetaObject metaObjectO1 = MetaObject.forObject(o1, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                        MetaObject metaObjectO2 = MetaObject.forObject(o2, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
                        for (String order : list) {
                            Object value1 = null;
                            String javaOrder = SqlUtil.toJavaProperty(order);
                            if (metaObjectO1.hasGetter(order)) {
                                value1 = metaObjectO1.getValue(order);
                            } else if (metaObjectO1.hasGetter(javaOrder)) {
                                value1 = metaObjectO1.getValue(javaOrder);
                            } else {
                                throw new RuntimeException("没有值");
                            }

                            Object value2 = null;
                            if (metaObjectO2.hasGetter(order)) {
                                value2 = metaObjectO2.getValue(order);
                            } else if (metaObjectO2.hasGetter(javaOrder)) {
                                value2 = metaObjectO2.getValue(javaOrder);
                            } else {
                                throw new RuntimeException("没有值");
                            }
                            // long,int 比较都是用 equals
                            if (value1.equals(value2)) {
                                continue;
                            }
                            if (value1 instanceof String) {
                                if (((String) value1).equalsIgnoreCase((String) value2)) {
                                    continue;
                                }
                                return ((String) value1).compareTo((String) value2);
                            } else if (value1 instanceof Long) {
                                return ((Long) value1).compareTo((Long) value2);
                            } else if (value1 instanceof Integer) {
                                return ((Integer) value1).compareTo((Integer) value2);
                            } else if (value1 instanceof Double) {
                                return ((Double) value1).compareTo((Double) value2);
                            } else if (value1 instanceof Float) {
                                return ((Float) value1).compareTo((Float) value2);
                            }
                        }
                        return 0;
                    }
                }).collect(Collectors.toList());
                res[0] = collect;
                return super.visit(orderBy);
            }
        });
    }

    private static void reWriteLimit(MySqlSelectQueryBlock sqlSelectQuery, String finalId, Object[] res) {
        sqlSelectQuery.accept(new SQLASTVisitorAdapter() {
            // Limit 改写
            @Override
            public boolean visit(SQLLimit sqlLimit) {
                Map<String, String> map = LimitHolder.get();
                if (!map.containsKey(finalId)) {
                    return super.visit(sqlLimit);
                }
                String limit = map.get(finalId);
                String[] split = limit.split(":");
                int offset = Integer.parseInt(split[0]);
                int count = Integer.parseInt(split[1]);
                List<Object> tmp = (List<Object>) res[0];
                int size = tmp.size();
                if (offset >= size) {
                    res[0] = new ArrayList<>();
                } else if (count + offset > size) {
                    res[0] = tmp.subList(offset, size);
                } else {
                    res[0] = tmp.subList(offset, offset + count);
                }
                return super.visit(sqlLimit);
            }
        });
    }

    private Map<String, List<Object>> getGroupByMap(List<Object> tmp, List<String> groupByItems) {
        Map<String, List<Object>> map = new HashMap<>();
        for (Object obj : tmp) {
            StringBuilder sb = new StringBuilder();
            MetaObject metaObject = MetaObject.forObject(obj, DEFAULT_OBJECT_FACTORY,
                    DEFAULT_OBJECT_WRAPPER_FACTORY, DEFAULT_REFLECTOR_FACTORY);
            for (String groupByItem : groupByItems) {
                if (metaObject.hasGetter(groupByItem)) {
                    sb.append(metaObject.getValue(groupByItem)).append(":");
                } else if (metaObject.hasGetter(SqlUtil.toJavaProperty(groupByItem))) {
                    sb.append(metaObject.getValue(SqlUtil.toJavaProperty(groupByItem))).append(":");
                } else {
                    sb.append("null").append(":");
                }
            }

            String key = sb.deleteCharAt(sb.length() - 1).toString();
            if (!map.containsKey(key)) {
                map.put(key, new ArrayList<>());
            }
            map.get(key).add(obj);
        }
        return map;
    }

    private SQLSelectItem findSelectItem(SQLAggregateExpr expr) {
        SQLObject parent = expr.getParent();
        while (!(parent instanceof SQLSelectItem)) {
            parent = parent.getParent();
        }
        return (SQLSelectItem) parent;
    }

    private boolean isLong(Object ele) {
        return (ele instanceof Long) || (ele.getClass().isAssignableFrom(long.class));
    }

    private boolean isInteger(Object ele) {
        return (ele instanceof Integer) || (ele.getClass().isAssignableFrom(int.class));
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
